package com.wugh.fast.demo.config.bean;

import com.wugh.fast.kernel.core.enums.FastExceptionEnum;
import com.wugh.fast.kernel.core.exception.FastBusinessException;
import com.wugh.fast.module.api.vo.ResponseVO;
import feign.Response;
import feign.Util;
import feign.codec.Decoder;

import java.io.IOException;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Optional;

/**
 * 说明: FeignClient响应解析
 * <pre>
 *     通过解析器,判断ResponseVO的code,如果不为0直接抛出异常
 * </pre>
 *
 * @author wugh
 * @date 2020-01-02 17:03
 */
public class ResponseDecoder implements Decoder {
    final Decoder delegate;

    public ResponseDecoder(Decoder delegate) {
        this.delegate = delegate;
    }

    @Override
    public Object decode(Response response, Type type) throws IOException {
        if (!isOptional(type)) {
            return checkAndReturnResponseVO(delegate.decode(response, type), type);
        }
        if (response.status() == 404 || response.status() == 204) {
            return Optional.empty();
        }
        Type enclosedType = Util.resolveLastTypeParameter(type, Optional.class);
        return Optional.ofNullable(checkAndReturnResponseVO(delegate.decode(response, enclosedType), enclosedType));
    }

    protected Object checkAndReturnResponseVO(Object result, Type type) {
        if (isResponseVO(type) && result != null) {
            ResponseVO response = (ResponseVO) result;
            if (!FastExceptionEnum.SUCCESS.getCode().equals(response.getCode())) {
                throw new FastBusinessException(response.getCode(), response.getMsg());
            }
        }
        return result;
    }

    static boolean isResponseVO(Type type) {
        if (!(type instanceof ParameterizedType)) {
            return false;
        }
        ParameterizedType parameterizedType = (ParameterizedType) type;
        return parameterizedType.getRawType().equals(ResponseVO.class);
    }

    static boolean isOptional(Type type) {
        if (!(type instanceof ParameterizedType)) {
            return false;
        }
        ParameterizedType parameterizedType = (ParameterizedType) type;
        return parameterizedType.getRawType().equals(Optional.class);
    }
}
